package com.such.kitx.tax.agent;

import java.util.Arrays;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import com.such.kit.Logger;
import com.such.kit.jna.JNACommons;
import com.such.kit.jna.bean.JNativeArg;
import com.such.kit.resource.support.ReadResource;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * DLL 调用代理服务
 * DLL 一般只能在 window 环境下使用，在后台以 DLL、COM 的方式调用税控服务会限制系统的部署环境
 * 因此需要编写一个代理服务，通过代理、中转的方式调用部署在 window 环境下的税控服务
 * 此服务基于 WebService 实现，目前航信税控服务已统一到 WebService 接口，选择 WebService 作为跨平台的代理服务也可以做到一定程度的技术统一
 * </pre>
 */
@WebService
public class AgentServer {

	/** INTERFACE_TYPE_DLL：DLL 接口，其接口形式为 void OperateDisk(LPCSTR sInputInfo, LPSTR sOutputInfo) */
	public static final String INTERFACE_TYPE_DLL = "DLL";
	/** INTERFACE_TYPE_COM：COM 接口，其接口形式为String OperateDisk(LPCSTR sInputInfo) */
	public static final String INTERFACE_TYPE_COM = "COM";

	private static String resourceName = "tax-agent";

	private String interfaceType;
	private String env;
	private String mainLib;
	private String mainFunc;

	/**
	 * <pre>
	 * [参考 {@link #start(String, String, String, String, String, String...)}]
	 * </pre>
	 */
	private AgentServer(String interfaceType, String env, String mainLib, String mainFunc, String... libs) {
		this.interfaceType = interfaceType;
		this.env = env;
		this.mainLib = mainLib;
		this.mainFunc = mainFunc;
		if (ValidateCommons.isNotEmpty(libs)) {
			for (String lib : libs) {
				Logger.debug(getClass(), StringCommons.merger("加载库 [", lib, "]"));
				System.load(lib);
			}
		}
	}

	/**
	 * <pre>
	 * 执行方法
	 * </pre>
	 * @param request 请求报文
	 * @return 响应报文
	 * @throws IllegalAccessException
	 * @throws NativeException
	 */
	@WebMethod(action="invoke")
	@WebResult(name="response")
	public String invoke(@WebParam(name="request") String request) 
			throws IllegalAccessException, NativeException {
		String response = null;
		if (INTERFACE_TYPE_DLL.equals(this.interfaceType)) {
			response = JNACommons.invokeByJNative(this.env, this.mainLib, this.mainFunc, new JNativeArg(Type.PSTRUCT, request), new JNativeArg(Type.PSTRUCT));
		} else if (INTERFACE_TYPE_COM.equals(this.interfaceType)) {
			response = JNACommons.invokeByJacob(this.env, this.mainLib, this.mainFunc, request);
		}
		return response;
	}

	/**
	 * <pre>
	 * 启动代理服务
	 * 
	 * env、lib 根据 interfaceType 的不同，具体含义有所差别
	 *   {@link #INTERFACE_TYPE_DLL} [参考 {@link JNACommons#invokeByJNative(String, String, String, JNativeArg...)}]
	 *   {@link #INTERFACE_TYPE_COM} [参考 {@link JNACommons#invokeByJacob(String, String, String, Object...)}]
	 * </pre>
	 * @param address WebService 服务地址
	 * @param interfaceType 税控服务接口类型 [参考 INTERFACE_TYPE_*]
	 * @param env 环境
	 * @param mainLib 需要调用的库
	 * @param mainFunc 需要调用的函数
	 * @param libs mainLib 的依赖库
	 */
	public static void start(String address, String interfaceType, String env, String mainLib, String mainFunc, String... libs) {
		Logger.debug(AgentServer.class, "Tax DLL 调用代理启动.开始");
		Endpoint.publish(address, new AgentServer(interfaceType, env, mainLib, mainFunc, libs));
		Logger.debug(AgentServer.class, "Tax DLL 调用代理启动.完成");
	}

	/**
	 * <pre>
	 * 主方法
	 * 为脚本启动提供入口
	 * </pre>
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		int argLen = args.length;
		if (argLen == 0) {
			Logger.info(AgentServer.class, "从 tax-agent.properties 中加载配置");
			List<String> keys = ReadResource.getKeys(resourceName);
			if (ValidateCommons.isNotEmpty(keys)) {
				argLen = keys.size();
				args = new String[argLen];
				for (int i = 0; i < argLen; i++) {
					args[i] = ReadResource.getValue(resourceName, keys.get(i));
				}
			}
		}
		if (argLen < 5) {
			throw new Exception("缺少关键参数 [WebService 服务地址, 税控服务接口类型, 运行环境库, 需要调用的库, 需要调用的函数]");
		}
		String address = args[0];
		String interfaceType = args[1];
		String env = args[2];
		String mainLib = args[3];
		String mainFunc = args[4];
		String[] libs = new String[0];
		if (argLen > 5) {
			libs = Arrays.copyOfRange(args, 5, argLen);
		}
		AgentServer.start(address, interfaceType, env, mainLib, mainFunc, libs);
	}

}
